package org.lmind.example.common.web;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.apache.commons.collections.iterators.IteratorEnumeration;

public class VirtualFilter implements Filter {
	
	private Collection<Filter> filters;
	
	public VirtualFilter() {
		this.filters = new ArrayList<Filter>();
	}
	
	public VirtualFilter(Collection<Filter> filters) {
		this.filters = filters;
	}

	public void appendFilters(Collection<Filter> filters) {
		if (filters == null)
			return;
		this.filters.addAll(filters);
	}

	public void init(FilterConfig filterConfig) throws ServletException {
		EmptyFilterConfig config = new EmptyFilterConfig();
		config.setServletContext(filterConfig.getServletContext());
		for (Filter filter : filters) {
			filter.init(config);
		}
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		VirtualFilterChain head = new VirtualFilterChain(null);
		VirtualFilterChain next = head;
		for (Filter filter : filters) {
			next.setCurrentFilter(filter);
			next = new VirtualFilterChain(next);
		}
		
		next.setCurrentFilter(new LastFilter(chain));
		next = new VirtualFilterChain(next);
		
		head.doFilter(request, response);
	}

	public void destroy() {
		for (Filter filter : filters) {
			filter.destroy();
		}
	}
	
	static class EmptyFilterConfig implements FilterConfig {
		
		private static final ArrayList<String> EMPTY_PARAMETER = new ArrayList<String>();
		
		private ServletContext servletContext;

		public void setServletContext(ServletContext servletContext) {
			this.servletContext = servletContext;
		}

		@Override
		public String getFilterName() {
			return "";
		}

		@Override
		public ServletContext getServletContext() {
			return servletContext;
		}

		@Override
		public String getInitParameter(String name) {
			return null;
		}

		@SuppressWarnings("rawtypes")
		@Override
		public Enumeration getInitParameterNames() {
			return new IteratorEnumeration(EMPTY_PARAMETER.iterator());
		}
		
	}
	
	
	class VirtualFilterChain implements FilterChain {
		
		private boolean discard = false;
		
		private Filter currentFilter;
		
		private VirtualFilterChain nextChain;

		public VirtualFilterChain(VirtualFilterChain prev) {
			if (prev != null)
				prev.nextChain = this;
		}

		public void setCurrentFilter(Filter currentFilter) {
			this.currentFilter = currentFilter;
		}

		public void setNextChain(VirtualFilterChain nextChain) {
			this.nextChain = nextChain;
		}

		@Override
		public void doFilter(ServletRequest request, ServletResponse response)
				throws IOException, ServletException {
			if (discard)
				throw new ServletException("FilterChain的doFilter出现重复调用");
			discard = true;
			
			if (nextChain != null) {
				nextChain.discard = false;
				currentFilter.doFilter(request, response, nextChain);
			}
		}
		
	}
	
	
	class LastFilter implements Filter {
		
		private FilterChain originFilterChain;

		public LastFilter(FilterChain originFilterChain) {
			this.originFilterChain = originFilterChain;
		}

		@Override
		public void init(FilterConfig filterConfig) throws ServletException {}

		@Override
		public void doFilter(ServletRequest request, ServletResponse response,
				FilterChain chain) throws IOException, ServletException {
			originFilterChain.doFilter(request, response);
		}

		@Override
		public void destroy() {}
		
	}

}
